package core.proto.vis.controls;

import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;

import core.util.logging.UserLogWriter;
import core.util.logging.constants.Action;
import core.util.logging.constants.Location;

import prefuse.Display;
import prefuse.Visualization;
import prefuse.controls.Control;
import prefuse.controls.ControlAdapter;
import prefuse.util.GraphicsLib;
import prefuse.util.display.DisplayLib;
import prefuse.util.ui.UILib;
import prefuse.visual.VisualItem;

public class ZoomToFitControl extends ControlAdapter
{
    private long m_duration = 2000;

    private int m_margin = 50;

    private int m_button = RIGHT_MOUSE_BUTTON;

    private boolean m_zoomOverItem = true;

    private String m_group = Visualization.ALL_ITEMS;

    /**
     * Create a new ZoomToFitControl.
     */
    public ZoomToFitControl() {
    }

    /**
     * Create a new ZoomToFitControl.
     * 
     * @param group
     *            the data group that should fit the Display
     */
    public ZoomToFitControl( String group ) {
        this.m_group = group;
    }

    /**
     * Create a new ZoomToFitControl.
     * 
     * @param button
     *            the mouse button used to initiate the zoom-to-fit. One of
     *            {@link Control#LEFT_MOUSE_BUTTON},
     *            {@link Control#MIDDLE_MOUSE_BUTTON}, or
     *            {@link Control#RIGHT_MOUSE_BUTTON}.
     */
    public ZoomToFitControl( int button ) {
        this.m_button = button;
    }

    /**
     * Create a new ZoomToFitControl.
     * 
     * @param group
     *            the data group that should fit the Display
     * @param button
     *            the mouse button used to initiate the zoom-to-fit. One of
     *            {@link Control#LEFT_MOUSE_BUTTON},
     *            {@link Control#MIDDLE_MOUSE_BUTTON}, or
     *            {@link Control#RIGHT_MOUSE_BUTTON}.
     */
    public ZoomToFitControl( String group, int button ) {
        this.m_group = group;
        this.m_button = button;
    }

    /**
     * Create a new ZoomToFitControl.
     * 
     * @param group
     *            the data group that should fit the Display
     * @param margin
     *            the margin, in pixels, desired between the group and the edge
     *            of the display
     * @param duration
     *            the duration of the animated zoom
     * @param button
     *            the mouse button used to initiate the zoom-to-fit. One of
     *            {@link Control#LEFT_MOUSE_BUTTON},
     *            {@link Control#MIDDLE_MOUSE_BUTTON}, or
     *            {@link Control#RIGHT_MOUSE_BUTTON}.
     */
    public ZoomToFitControl( String group, int margin, long duration, int button ) {
        this.m_group = group;
        this.m_margin = margin;
        this.m_duration = duration;
        this.m_button = button;
    }

    /**
     * @see prefuse.controls.Control#itemClicked(prefuse.visual.VisualItem,
     *      java.awt.event.MouseEvent)
     */
    public void itemClicked( VisualItem item, MouseEvent e ) {
        if( m_zoomOverItem )
            mouseClicked( e );
    }

    /**
     * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
     */
    public void mouseClicked( MouseEvent e ) {
        Display display = (Display) e.getComponent();
        if( !display.isTranformInProgress()
                && UILib.isButtonPressed( e, m_button ) ) {
            Visualization vis = display.getVisualization();
            Rectangle2D bounds = vis.getBounds( m_group );
            GraphicsLib.expand( bounds,
                    m_margin + (int) (1 / display.getScale()) );
            DisplayLib.fitViewToBounds( display, bounds, m_duration );
            UserLogWriter.log( "Zoom to fit", Location.Viz, Action.getClicks(e.getClickCount()));
        }
    }

    /**
     * Indicates if the zoom control will work while the mouse is over a
     * VisualItem.
     * 
     * @return true if the control still operates over a VisualItem
     */
    public boolean isZoomOverItem() {
        return m_zoomOverItem;
    }

    /**
     * Determines if the zoom control will work while the mouse is over a
     * VisualItem
     * 
     * @param zoomOverItem
     *            true to indicate the control operates over VisualItems, false
     *            otherwise
     */
    public void setZoomOverItem( boolean zoomOverItem ) {
        this.m_zoomOverItem = zoomOverItem;
    }

    /**
     * Get the display margin to include within the "zoomed-to-fit" bounds.
     * 
     * @return Display margin currently in use
     */
    public int getMargin() {
        return m_margin;
    }

    /**
     * Set the display margin to include within the "zoomed-to-fit" bounds.
     * 
     * @param margin
     *            Display margin to use
     */
    public void setMargin( int margin ) {
        this.m_margin = margin;
    }

} // end of class ZoomToFitControl
